package cn.fintecher.pangolin.service.dataimp.task;

import cn.fintecher.pangolin.common.enums.CancelCategory;
import cn.fintecher.pangolin.common.enums.ImportDataExcelStatus;
import cn.fintecher.pangolin.common.model.UserModel;
import cn.fintecher.pangolin.common.utils.ZWDateUtil;
import cn.fintecher.pangolin.entity.elastic.BaseCase;
import cn.fintecher.pangolin.entity.elastic.DataImportRecord;
import cn.fintecher.pangolin.entity.elastic.PaymentRecord;
import cn.fintecher.pangolin.entity.elastic.PaymentRecordModel;
import cn.fintecher.pangolin.entity.mysql.AssistCase;
import cn.fintecher.pangolin.entity.mysql.CaseInfo;
import cn.fintecher.pangolin.service.dataimp.elastic.BaseCaseElastic;
import cn.fintecher.pangolin.service.dataimp.elastic.DataImportRecordElastic;
import cn.fintecher.pangolin.service.dataimp.elastic.PaymentRecordElastic;
import cn.fintecher.pangolin.service.dataimp.elastic.PaymentRecordModelElastic;
import cn.fintecher.pangolin.service.dataimp.model.BillModel;
import cn.fintecher.pangolin.service.dataimp.model.CancelBillModel;
import cn.fintecher.pangolin.service.dataimp.repository.AssistCaseRepository;
import cn.fintecher.pangolin.service.dataimp.repository.CaseInfoRepository;
import cn.fintecher.pangolin.common.utils.RepositoryUtil;
import com.google.common.collect.Lists;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
 * @Auther: xiaqun
 * @Description:
 * @Date: 10:46 2019/11/13
 */

@Service("cancelBillTask")
public class CancelBillTask {
    private static final Logger log = LoggerFactory.getLogger(CancelBillTask.class);

    @Autowired
    private BaseCaseElastic baseCaseElastic;

    @Autowired
    private CaseInfoRepository caseInfoRepository;

    @Autowired
    private PaymentRecordElastic paymentRecordElastic;

    @Autowired
    private PaymentRecordModelElastic paymentRecordModelElastic;

    @Autowired
    private DataImportRecordElastic dataImportRecordElastic;

    @Autowired
    private CancelBillFuture cancelBillFuture;

    @Autowired
    private AssistCaseRepository assistCaseRepository;

    /**
     * 对账单撤销操作
     */
    @Async
    @Transactional
    public void processCancelBill(List<PaymentRecordModel> list, DataImportRecord dataImportRecord, String batchNumber, UserModel userModel, CancelCategory cancelCategory) {
        List<CompletableFuture<Map<String, CancelBillModel>>> futureList = new ArrayList<>();
        //分页处理信息
        int pageSize = 2000;
        int pageNumber = (int) Math.ceil((double) list.size() / (double) pageSize);
        for (int i = 0; i < pageNumber; i++) {
            List<PaymentRecordModel> models = list.stream().skip(i * pageSize).limit(pageSize).collect(Collectors.toList());
            CompletableFuture<Map<String, CancelBillModel>> task = cancelBillFuture.processBill(models);
            futureList.add(task);
        }
        try {
            Map<String, CancelBillModel> map = new HashMap<>();
            for (CompletableFuture<Map<String, CancelBillModel>> future : futureList) {
                Map<String, CancelBillModel> modelMap = future.get();
                for (Map.Entry<String, CancelBillModel> entry : modelMap.entrySet()) {
                    if (map.containsKey(entry.getKey())) {
                        CancelBillModel oldModel = map.get(entry.getKey());
                        CancelBillModel newModel = entry.getValue();
                        oldModel.getPaymentRecords().addAll(newModel.getPaymentRecords());
                        oldModel.getPaymentRecordModels().addAll(newModel.getPaymentRecordModels());
                        map.put(entry.getKey(), oldModel);
                    } else {
                        map.put(entry.getKey(), entry.getValue());
                    }
                }
            }
            List<BaseCase> baseCaseList = new ArrayList<>();
            List<CaseInfo> caseInfoList = new ArrayList<>();
            List<AssistCase> assistCaseList = new ArrayList<>();
            List<PaymentRecord> paymentRecordList = new ArrayList<>();
            List<PaymentRecordModel> paymentRecordModelList = new ArrayList<>();
            List<CompletableFuture<BillModel>> futures = new ArrayList<>();
            for (Map.Entry<String, CancelBillModel> entry : map.entrySet()) {
                CompletableFuture<BillModel> future = cancelBillFuture.processStatus(entry, userModel);
                futures.add(future);
            }
            for (CompletableFuture<BillModel> future : futures) {
                BillModel model = future.get();
                if (Objects.nonNull(model.getBaseCase())) {
                    baseCaseList.add(model.getBaseCase());
                }
                if (Objects.nonNull(model.getCaseInfo())) {
                    caseInfoList.add(model.getCaseInfo());
                }
                if (Objects.nonNull(model.getAssistCases())) {
                    assistCaseList.addAll(model.getAssistCases());
                }
                if (Objects.nonNull(model.getPaymentRecords())) {
                    paymentRecordList.addAll(model.getPaymentRecords());
                }
                if (Objects.nonNull(model.getPaymentRecordModels())) {
                    paymentRecordModelList.addAll(model.getPaymentRecordModels());
                }
            }
            RepositoryUtil.saveData(paymentRecordElastic, paymentRecordList);
            RepositoryUtil.saveData(paymentRecordModelElastic, paymentRecordModelList);
            RepositoryUtil.saveData(baseCaseElastic, baseCaseList);
            RepositoryUtil.saveData(caseInfoRepository, caseInfoList);
            RepositoryUtil.saveData(assistCaseRepository, assistCaseList);
            //更改导入结果状态
            if (Objects.equals(cancelCategory, CancelCategory.BATCH)) {
                dataImportRecord.setStatus(ImportDataExcelStatus.BILL_REVOKE);
            } else {
                BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
                boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("batchNumber.keyword", batchNumber));
                List<PaymentRecordModel> paymentRecordModels = Lists.newArrayList(paymentRecordModelElastic.search(boolQueryBuilder));
                long count = paymentRecordModels.stream().filter(model -> Objects.equals(model.getFlag(), 0)).count();
                if (count == 0) {
                    dataImportRecord.setStatus(ImportDataExcelStatus.BILL_REVOKE);
                } else {
                    dataImportRecord.setStatus(ImportDataExcelStatus.CONFIRMED);
                }
            }
            dataImportRecord.process(userModel.getRealName(), ZWDateUtil.getNowDateTime());
            dataImportRecordElastic.save(dataImportRecord);
        } catch (InterruptedException | ExecutionException e) {
            log.error(e.getMessage(), e);
        }
    }
}
